package com.wuze.cloud.service.impl;

import com.wuze.cloud.adapter.SysUserAdapter;
import com.wuze.cloud.context.RedisContext;
import com.wuze.cloud.context.UserContext;
import com.wuze.cloud.dao.*;
import com.wuze.cloud.exception.SysGlobalException;
import com.wuze.cloud.model.SysRegisterData;
import com.wuze.cloud.model.SysUploadData;
import com.wuze.cloud.pojo.SysFolderDO;
import com.wuze.cloud.pojo.SysStorageDO;
import com.wuze.cloud.pojo.SysUserDO;
import com.wuze.cloud.request.*;
import com.wuze.cloud.response.SysUserInfoPageResponse;
import com.wuze.cloud.response.SysUserPageResponse;
import com.wuze.cloud.response.SysUserResponse;
import com.wuze.cloud.service.SysUserService;
import com.wuze.cloud.util.JwtUtil;
import com.wuze.cloud.util.MailUtil;
import com.wuze.cloud.util.Md5Util;
import com.wuze.cloud.util.RedisUtil;
import lombok.extern.slf4j.Slf4j;
import org.assertj.core.util.Lists;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Objects;

import static com.wuze.cloud.enums.SysGlobalExceptionEnum.*;
import static com.wuze.cloud.enums.SysUserRoleEnum.ROOT;
import static com.wuze.cloud.enums.SysUserRoleEnum.SIMPLE;
import static com.wuze.cloud.enums.SysUserStateEnum.CENCEL;
import static com.wuze.cloud.enums.SysUserStateEnum.UN_CENCEL;

/**
 * @author: wuze
 * @description:
 * @date: 2023/02/16
 */
@Service
@Slf4j
public class SysUserServiceImpl implements SysUserService {

    @Autowired
    private SysUserAdapter userAdapter;

    @Autowired
    private SysUserDao userDao;

    @Autowired
    private SysFolderDao folderDao;

    @Autowired
    private SysStorageDao storageDao;

    @Autowired
    private SysShareDao shareDao;

    @Autowired
    private RedisUtil redisUtil;

    @Autowired
    private MailUtil mailUtil;

    @Autowired
    private SysFileDao fileDao;

    /**
     * 分页查询用户信息
     *
     * @param query
     * @return
     */
    @Override
    public SysUserPageResponse findByPage(SysUserQuery query) {
        //鉴权
        SysUserDO user = UserContext.getUser();
        if (!user.getRole().equals(ROOT.getCode())) {
            throw new SysGlobalException(USER_AUTH_ERR.getCode(), USER_AUTH_ERR.getMsg());
        }
        SysUserPageResponse response = new SysUserPageResponse();
        Integer count = userDao.countAdmin(query);
        response.setTotal(count);
        if (count == 0) {
            response.setUsers(Lists.newArrayList());
            return response;
        }
        List<SysUserDO> users = userDao.findByPageAdmin(query);
        response.setUsers(userAdapter.buildSysUserVOList(users));
        return response;
    }

    /**
     * 分页查询用户信息-空间信息
     *
     * @param query
     * @return
     */
    @Override
    public SysUserInfoPageResponse findByPageV2(SysUserQuery query) {
        //鉴权
        SysUserDO user = UserContext.getUser();
        if (!user.getRole().equals(ROOT.getCode())) {
            throw new SysGlobalException(USER_AUTH_ERR.getCode(), USER_AUTH_ERR.getMsg());
        }
        SysUserInfoPageResponse response = new SysUserInfoPageResponse();
        Integer count = userDao.count(query, UN_CENCEL.name());
        response.setTotal(count);
        if (count == 0) {
            response.setUsers(Lists.newArrayList());
            return response;
        }
        List<SysUserDO> users = userDao.findByPage(query, UN_CENCEL.name());
        response.setUsers(userAdapter.buildSysUserInfoVOList(users));
        return response;
    }

    /**
     * 用户/管理员登录校验
     *
     * @param query 封装登录请求实体
     * @return SysUserResponse
     */
    @Override
    public SysUserResponse login(SysLoginUserQuery query) {
        //登录校验
        SysUserDO user = verifyUserLogin(query);
        //封装token
        String token = JwtUtil.createJWT(user);
        return userAdapter.buildSysUserResponses(user, token);
    }

    /**
     * 校验登录请求
     *
     * @param query
     * @return
     */
    private SysUserDO verifyUserLogin(SysLoginUserQuery query) {

        SysUserDO user = userDao.findByUserName(query.getUserName(), UN_CENCEL.name());
        //校验用户名是否存在
        if (Objects.isNull(user)) {
            user = userDao.findByEmail(query.getUserName());
            if (Objects.isNull(user)) {
                throw new SysGlobalException(USER_EMPTY.getCode(), USER_EMPTY.getMsg());
            }
        }
        //校验身份是否正确
        if (!user.getRole().equals(query.getRole())) {
            throw new SysGlobalException(ROLE_ERROR.getCode(), ROLE_ERROR.getMsg());
        }
        //校验密码是否正确
        if (!user.getPassword().equals(Md5Util.getMD5Pwd(query.getPassword(), user.getSalt()))) {
            throw new SysGlobalException(PASSWORD_ERROR.getCode(), PASSWORD_ERROR.getMsg());
        }
        return user;
    }


    /**
     * 用户注册获取验证码
     *
     * @param query
     */
    @Override
    public void getCodeByRegister(SysGetCodeQuery query) {

        //校验请求
        verifyEmail(query);

        String code = mailUtil.generateVerifyCode(6);
        mailUtil.sendAuthCodeEmail(query.getEmail(), code);
        redisUtil.setex(query.getEmail(), code, 5 * 60);

    }

    /**
     * 用户注册获取验证码请求校验
     *
     * @param query
     */
    public void verifyEmail(SysGetCodeQuery query) {
        if (!mailUtil.isEmail(query.getEmail())) {

            throw new SysGlobalException(EMAIL_ERR.getCode(), EMAIL_ERR.getMsg());
        }
        SysUserDO user = userDao.findByEmail(query.getEmail());
        if (Objects.nonNull(user)) {
            throw new SysGlobalException(EMAIL_REPEAT.getCode(), EMAIL_REPEAT.getMsg());
        }
        if (Objects.nonNull(redisUtil.get(query.getEmail()))) {
            throw new SysGlobalException(CODE_SEND.getCode(), CODE_SEND.getMsg());
        }
    }


    /**
     * 用户注册
     *
     * @param query
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void register(SysCreateUserQuery query) {

        //校验请求
        verifySysRegisterUserQuery(query);
        //构建用户实体
        SysUserDO userDO = userAdapter.buildSysUserDO(query);
        //创建根目录
        SysFolderDO folderDO = SysFolderDO.createRoot(userDO.getId());
        //创建存储表
        SysStorageDO storage = SysStorageDO.get(userDO.getId());

        //保存存储信息
        storageDao.add(storage);
        //保存根目录
        folderDao.save(folderDO);

        //保存用户数据
        userDO.setRootId(folderDO.getId());
        userDao.addSysUser(userDO);
        redisUtil.del(query.getEmail());
    }

    /**
     * 校验用户注册请求
     *
     * @param query
     */
    private void verifySysRegisterUserQuery(SysCreateUserQuery query) {

        SysUserDO sysUserDO = userDao.findByUserName(query.getUserName(), UN_CENCEL.name());

        if (Objects.nonNull(sysUserDO)) {
            throw new SysGlobalException(USERNAME_REPEAT.getCode(), USERNAME_REPEAT.getMsg());
        }
        sysUserDO = userDao.findByPhone(query.getPhone(), UN_CENCEL.name());
        if (Objects.nonNull(sysUserDO)) {
            throw new SysGlobalException(PHONE_REPEAT.getCode(), PHONE_REPEAT.getMsg());
        }

        if (!mailUtil.isEmail(query.getEmail())) {
            throw new SysGlobalException(EMAIL_ERR.getCode(), EMAIL_ERR.getMsg());
        }
        sysUserDO = userDao.findByEmail(query.getEmail());
        if (Objects.nonNull(sysUserDO)) {
            throw new SysGlobalException(EMAIL_REPEAT.getCode(), EMAIL_REPEAT.getMsg());
        }
        String code = (String) redisUtil.get(query.getEmail());
        if (StringUtils.isEmpty(code)) {
            throw new SysGlobalException(NOT_CODE.getCode(), NOT_CODE.getMsg());
        }
        if (!query.getCode().equals(code)) {
            throw new SysGlobalException(CODE_ERR.getCode(), CODE_ERR.getMsg());
        }

    }

    /**
     * 获取重置密码验证码
     *
     * @param query
     */
    @Override
    public void getCodeByResetPwd(SysGetCodeQuery query) {
        //校验请求
        verifyEmailByResetPwd(query);

        String code = mailUtil.generateVerifyCode(6);
        mailUtil.sendAuthCodeEmail(query.getEmail(), code);
        redisUtil.setex(query.getEmail(), code, 5 * 60);

    }

    /**
     * 管理员/用户获取最近上传信息
     * @return
     */
    @Override
    public List<SysUploadData> getUploadInfo() {
        SysUserDO user = UserContext.getUser();
        SimpleDateFormat format = new SimpleDateFormat("yyyy/MM/dd");
        Date today = new Date();
        if(user.getRole().equals(SIMPLE.getCode())){
            //用户
            String key = RedisContext.USER_UPLOAD_DATA +format.format(today)+"_"+ user.getId();
            List<SysUploadData> data = (List<SysUploadData>)redisUtil.get(key);
            if(!CollectionUtils.isEmpty(data)){
                return data;
            }
            data = fileDao.getUploadData(user.getId());
            redisUtil.setex(RedisContext.USER_UPLOAD_DATA + format.format(today)+"_"+user.getId(),data,60*60*24);
            return data;
        }
        //管理员
        String key = RedisContext.ADMIN_UPLOAD_DATA+format.format(today);
        List<SysUploadData> data = (List<SysUploadData>)redisUtil.get(key);
        if(!CollectionUtils.isEmpty(data)){
            return data;
        }
        data = fileDao.getUploadData(null);
        redisUtil.setex(RedisContext.ADMIN_UPLOAD_DATA+format.format(today),data,60*60*24);
        return data;
    }

    /**
     * 管理员获取最近注册信息
     * @param role
     * @return
     */
    @Override
    public List<SysRegisterData> getRegisterInfo(String role) {
        //鉴权
        SysUserDO user = UserContext.getUser();
        if (!user.getRole().equals(ROOT.getCode())) {
            throw new SysGlobalException(USER_AUTH_ERR.getCode(), USER_AUTH_ERR.getMsg());
        }
        SimpleDateFormat format = new SimpleDateFormat("yyyy/MM/dd");
        Date today = new Date();
        List<SysRegisterData> data = (List<SysRegisterData>)redisUtil.get(RedisContext.REGISTER_DATA + format.format(today)+"_"+role);
        if(!CollectionUtils.isEmpty(data)){
            return data;
        }
        data = userDao.getRegisterData(role);
        redisUtil.setex(RedisContext.REGISTER_DATA + format.format(today)+"_"+role,data,60*60*24);
        return data;
    }

    /**
     * 用户找回密码获取验证码请求校验
     *
     * @param query
     */
    public void verifyEmailByResetPwd(SysGetCodeQuery query) {
        if (!mailUtil.isEmail(query.getEmail())) {
            throw new SysGlobalException(EMAIL_ERR.getCode(), EMAIL_ERR.getMsg());
        }
        SysUserDO user = userDao.findByEmail(query.getEmail());
        if (Objects.isNull(user)) {
            throw new SysGlobalException(EMAIL_EMPTY.getCode(), EMAIL_EMPTY.getMsg());
        }

        if (Objects.nonNull(redisUtil.get(query.getEmail()))) {
            throw new SysGlobalException(CODE_SEND.getCode(), CODE_SEND.getMsg());
        }

    }

    /**
     * 重置密码
     *
     * @param query
     */
    @Override
    public void resetPwd(SysResetPwdQuery query) {
        verifyResetPwdQuery(query);

        SysUserDO user = userDao.findByEmail(query.getEmail());

        user.setPassword(Md5Util.getMD5Pwd(query.getPassword(), user.getSalt()));

        userDao.updateUserInfo(user);
        redisUtil.del(query.getEmail());

    }

    /**
     * 用户重置密码请求校验
     *
     * @param query
     */
    public void verifyResetPwdQuery(SysResetPwdQuery query) {
        //校验邮箱格式
        if (!mailUtil.isEmail(query.getEmail())) {
            throw new SysGlobalException(EMAIL_ERR.getCode(), EMAIL_ERR.getMsg());
        }
        //校验密码是否正确
        if (!query.getPassword().equals(query.getRePassword())) {
            throw new SysGlobalException(PASSWORD_ERR.getCode(), PASSWORD_ERR.getMsg());
        }
        //校验邮箱是否存在
        SysUserDO user = userDao.findByEmail(query.getEmail());
        if (Objects.isNull(user)) {
            throw new SysGlobalException(EMAIL_EMPTY.getCode(), EMAIL_EMPTY.getMsg());
        }
        //校验验证码
        String code = (String) redisUtil.get(query.getEmail());
        if (StringUtils.isEmpty(code)) {
            throw new SysGlobalException(NOT_CODE.getCode(), NOT_CODE.getMsg());
        }
        if (!query.getCode().equals(code)) {
            throw new SysGlobalException(CODE_ERR.getCode(), CODE_ERR.getMsg());
        }
    }


    /**
     * 用户修改
     *
     * @param query
     * @return
     */
    @Override
    public SysUserResponse update(SysUpdateUserQuery query) {
        SysUserDO user = UserContext.getUser();
        //校验请求
        verifySysUpdateUserQuery(query);

        BeanUtils.copyProperties(query, user);
        user.setPassword(Md5Util.getMD5Pwd(query.getPassword(), user.getSalt()));

        userDao.updateUserInfo(user);
        //封装token
        String token = JwtUtil.createJWT(user);
        return userAdapter.buildSysUserResponses(user, token);
    }

    /**
     * 校验用户修改请求
     *
     * @param query
     */
    private void verifySysUpdateUserQuery(SysUpdateUserQuery query) {
        if (!mailUtil.isEmail(query.getEmail())) {
            throw new SysGlobalException(EMAIL_ERR.getCode(), EMAIL_ERR.getMsg());
        }
        SysUserDO user = UserContext.getUser();
        SysUserDO byUserName = userDao.findByUserName(query.getUserName(), UN_CENCEL.name());
        SysUserDO byPhone = userDao.findByPhone(query.getPhone(), UN_CENCEL.name());
        SysUserDO byEmail = userDao.findByEmail(query.getEmail());

        if (Objects.nonNull(byUserName) && !user.getId().equals(byUserName.getId())) {
            throw new SysGlobalException(USERNAME_REPEAT.getCode(), USERNAME_REPEAT.getMsg());
        }
        if (Objects.nonNull(byPhone) && !user.getId().equals(byPhone.getId())) {
            throw new SysGlobalException(PHONE_REPEAT.getCode(), PHONE_REPEAT.getMsg());
        }
        if (Objects.nonNull(byEmail) && !user.getId().equals(byEmail.getId())) {
            throw new SysGlobalException(EMAIL_REPEAT.getCode(), EMAIL_REPEAT.getMsg());
        }

    }

    /**
     * 创建管理员
     *
     * @param query
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void createAdmin(SysCreateUserQuery query) {
        //鉴权
        SysUserDO user = UserContext.getUser();
        if (!user.getRole().equals(ROOT.getCode())) {
            throw new SysGlobalException(USER_AUTH_ERR.getCode(), USER_AUTH_ERR.getMsg());
        }
        query.setRole(ROOT.getCode());
        //校验请求
        verifyCreateUserQuery(query);
        //构建用户实体
        SysUserDO userDO = userAdapter.buildSysUserDO(query);

        userDao.addSysUser(userDO);
    }

    /**
     * 校验创建管理员请求
     *
     * @param query
     */
    private void verifyCreateUserQuery(SysCreateUserQuery query) {
        if (!mailUtil.isEmail(query.getEmail())) {
            throw new SysGlobalException(EMAIL_ERR.getCode(), EMAIL_ERR.getMsg());
        }
        if (StringUtils.isEmpty(query.getPhone())) {
            throw new SysGlobalException(PHONE_EMPTY.getCode(), PHONE_EMPTY.getMsg());
        }
        SysUserDO byUserName = userDao.findByUserName(query.getUserName(), UN_CENCEL.name());
        SysUserDO byPhone = userDao.findByPhone(query.getPhone(), UN_CENCEL.name());
        SysUserDO byEmail = userDao.findByEmail(query.getEmail());
        if (Objects.nonNull(byUserName)) {
            throw new SysGlobalException(USERNAME_REPEAT.getCode(), USERNAME_REPEAT.getMsg());
        }
        if (Objects.nonNull(byPhone)) {
            throw new SysGlobalException(PHONE_REPEAT.getCode(), PHONE_REPEAT.getMsg());
        }
        if (Objects.nonNull(byEmail)) {
            throw new SysGlobalException(EMAIL_REPEAT.getCode(), EMAIL_REPEAT.getMsg());
        }

    }

    /**
     * 管理员批量删除用户
     * @param query
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void batchDeleteUser(SysDelUserQuery query) {
        //鉴权
        SysUserDO user = UserContext.getUser();
        if (!user.getRole().equals(ROOT.getCode())) {
            throw new SysGlobalException(USER_AUTH_ERR.getCode(), USER_AUTH_ERR.getMsg());
        }
        List<Long> userIds = query.getUserIds();
        shareDao.deleteByUserIds(userIds);
        userDao.updateStateByIds(userIds, CENCEL.name());
    }

    /**
     * 管理员修改用户/管理员信息
     *
     * @param query
     */
    @Override
    public void adminUpdate(SysAdminUpdateUserQuery query) {

        //校验请求
        verifySysAdminUpdateUserQuery(query);

        SysUserDO user = userDao.findById(query.getUserId(), UN_CENCEL.name());

        if (Objects.isNull(user)) {
            throw new SysGlobalException(USER_EMPTY.getCode(), USER_EMPTY.getMsg());
        }
        BeanUtils.copyProperties(query, user);
        user.setPassword(Md5Util.getMD5Pwd(query.getPassword(), user.getSalt()));
        userDao.updateUserInfo(user);

    }

    /**
     * 校验修改用户/管理员信息请求
     *
     * @param query
     */
    private void verifySysAdminUpdateUserQuery(SysAdminUpdateUserQuery query) {
        if (!mailUtil.isEmail(query.getEmail())) {
            throw new SysGlobalException(EMAIL_ERR.getCode(), EMAIL_ERR.getMsg());
        }
        SysUserDO user = userDao.findById(query.getUserId(), UN_CENCEL.name());
        SysUserDO byUserName = userDao.findByUserName(query.getUserName(), UN_CENCEL.name());
        SysUserDO byPhone = userDao.findByPhone(query.getPhone(), UN_CENCEL.name());
        SysUserDO byEmail = userDao.findByEmail(query.getEmail());

        if (Objects.nonNull(byUserName) && !user.getId().equals(byUserName.getId())) {
            throw new SysGlobalException(USERNAME_REPEAT.getCode(), USERNAME_REPEAT.getMsg());
        }
        if (Objects.nonNull(byPhone) && !user.getId().equals(byPhone.getId())) {
            throw new SysGlobalException(PHONE_REPEAT.getCode(), PHONE_REPEAT.getMsg());
        }
        if (Objects.nonNull(byEmail) && !user.getId().equals(byEmail.getId())) {
            throw new SysGlobalException(EMAIL_REPEAT.getCode(), EMAIL_REPEAT.getMsg());
        }
    }

}
